package com.simple.editor.vcs;

import com.simple.editor.callback.Callback;

import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * {@link AbstractVcsClient} provides async execution of VCS commands using single thread.
 * To avoid concurrent processing of VCS actions.
 * <p/>
 * Created with IntelliJ IDEA.
 * User: vsoroka
 * Date: 11.06.13
 * Time: 9:32
 * To change this template use File | Settings | File Templates.
 */
public abstract class AbstractVcsClient implements VcsClient {
    private final ExecutorService executorService = Executors.newSingleThreadExecutor();

    public Future<Void> refreshStatus(final Callback callback, final Collection<VcsFile> files) {
        final Callable<Void> task = new CallableWithCallback(callback) {
            @Override
            void run() throws Exception {
                doRefreshStatus(files);
            }
        };

        return executorService.submit(task);
    }

    public Future<Void> delete(final Callback callback, final Collection<VcsFile> files) {
        final Callable<Void> task = new CallableWithCallback(callback) {
            @Override
            void run() throws Exception {
                doDelete(files);
            }
        };

        return executorService.submit(task);
    }

    @Override
    public Future<Void> revert(final Callback callback, final Collection<VcsFile> files) {
        final Callable<Void> task = new CallableWithCallback(callback) {
            @Override
            void run() throws Exception {
                doRevert(files);
            }
        };

        return executorService.submit(task);
    }

    public Future<Void> commit(final Callback callback, final Collection<VcsFile> files) {
        final Callable<Void> task = new CallableWithCallback(callback) {
            @Override
            void run() throws Exception {
                doCommit(files);
            }
        };

        return executorService.submit(task);
    }

    public Future<Void> update(final Callback callback, final Collection<VcsFile> files) {
        final Callable<Void> task = new CallableWithCallback(callback) {
            @Override
            void run() throws Exception {
                doUpdate(files);
            }
        };

        return executorService.submit(task);
    }

    protected abstract void doRefreshStatus(Collection<VcsFile> file) throws VcsException;

    protected abstract void doDelete(Collection<VcsFile> files) throws VcsException;

    protected abstract void doRevert(Collection<VcsFile> files) throws VcsException;

    protected abstract void doCommit(Collection<VcsFile> files) throws VcsException;

    protected abstract void doUpdate(Collection<VcsFile> files) throws VcsException;

    private abstract static class CallableWithCallback implements Callable<Void> {
        private final Callback callback;

        protected CallableWithCallback(final Callback callback) {
            this.callback = callback;
        }

        @Override
        public Void call() throws Exception {
            try {
                callback.onStart();
                run();
                if (callback != null) {
                    callback.onComplete();
                }
            } catch (Exception ex) {
                if (callback != null) {
                    callback.onFailure(ex);
                } else {
                    throw ex;
                }
            }
            return null;
        }

        abstract void run() throws Exception;
    }
}
